/**
 * 
 */
package ua.lviv.franko.solvers.oneDimention;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;

import ua.lviv.franko.FEMShapeFunction1D.FEMShapeFunction1D1;
import ua.lviv.franko.FEMShapeFunction1D.IFEM1D;
import ua.lviv.franko.integration.GaussQuadrature;
import ua.lviv.franko.integration.IFunction1D;
import ua.lviv.franko.integration.Quadrature;
import ua.lviv.franko.mlsFunctions.oneDimension.BaseFunctionCoupled;
import ua.lviv.franko.mlsFunctions.oneDimension.ICalculate;
import ua.lviv.franko.mlsFunctions.oneDimension.ModifiedFEMBaseFunction;
import ua.lviv.franko.mlsFunctions.oneDimension.Particle;
import ua.lviv.franko.mlsFunctions.oneDimension.weightFunctions.CubicSpline;
import ua.lviv.franko.mlsFunctions.oneDimension.weightFunctions.IWeightFunction;
import ua.lviv.franko.solvers.ElementMatrix;
import ua.lviv.franko.solvers.IElement1D;
import ua.lviv.franko.visualisation.NewOkCancelDialog;

/**
 * @author marko
 * 
 */
public class EnrichedLinearElementType2 implements IElement1D {
	public int						QuadraturePointsNumber	= 20;

	// problem data
	protected EquationParameters	eParams;
	// element number starting from 0
	protected int					elNumber;
	// element information
	protected double				left;
	protected double				right;
	// results
	protected ElementMatrix			data;
	// EFG variables;
	protected int					degree					= 2;
	protected int					numberOfEFGNodes;
	protected IWeightFunction		weight;
	protected double				rho;

	private List<ICalculate>		baseFunctions;
	private List<Integer>			pos;

	public EnrichedLinearElementType2(EquationParameters eParams, double left, double right, int firstNumber, int numberOfEFGNodes, IWeightFunction weight, double rho) {
		this.elNumber = firstNumber;
		this.eParams = eParams;
		this.left = left;
		this.right = right;
		this.numberOfEFGNodes = numberOfEFGNodes;
		this.weight = weight;
		this.rho = rho;

		// create MLS funcs;
		// 1 create particles;
		double hEFG = (right - left) / (double) (numberOfEFGNodes);
		double rhoH = this.rho * hEFG;
		// FEM h;
		final double h = hEFG;
		ArrayList<Particle> ls1D = new ArrayList<Particle>();
		// for (int i = 0; i <= numberOfEFGNodes; i++) {
		for (int i = 0; i <= numberOfEFGNodes; i++) {
			ls1D.add(new Particle(left + hEFG * i, rhoH));
		}
		// 2 create functions
		ArrayList<IFEM1D> fem = new ArrayList<IFEM1D>();
		fem.add(new FEMShapeFunction1D1(left, h / 2.0));
		fem.add(new FEMShapeFunction1D1(right, h / 2.0));

		baseFunctions = new ArrayList<ICalculate>();

		ModifiedFEMBaseFunction mf = new ModifiedFEMBaseFunction(degree, ls1D.get(0), weight, fem, fem.get(0));
		mf.setNodeList(ls1D);
		baseFunctions.add(mf);
		// baseFunctions.add((ICalculate) fem.get(0));
		for (int i = 1; i < ls1D.size() - 1; i++) {
			// for (int i = 0; i < ls1D.size(); i++) {
			Particle particle = ls1D.get(i);
			BaseFunctionCoupled jmf1 = new BaseFunctionCoupled(degree, particle, weight, fem);
			jmf1.setNodeList(ls1D);
			baseFunctions.add(jmf1);
		}
		mf = new ModifiedFEMBaseFunction(degree, ls1D.get(ls1D.size() - 1), weight, fem, fem.get(1));
		mf.setNodeList(ls1D);
		baseFunctions.add(mf);
		// baseFunctions.add((ICalculate) fem.get(1));

		pos = new ArrayList<Integer>();
		for (int i = 0; i < baseFunctions.size(); i++) {
			pos.add(this.elNumber + i);
		}

		// display functions ...
		XYSeriesCollection col = new XYSeriesCollection();
		// int position = 0;
		for (Iterator<ICalculate> iterator = baseFunctions.iterator(); iterator.hasNext();) {
			double hDer = 0.0001;
			ICalculate jmf1 = iterator.next();
			XYSeries s = new XYSeries("1", true, true);
			double xxx = left;
			while (xxx <= right + 0.0001) {
//				double tmp1 = (jmf1.calculate(xxx) - jmf1.calculate(xxx+hDer))/hDer;
				double tmp1 = (jmf1.calculate(xxx));
				s.add(xxx, tmp1);
				xxx += 0.0002;
			}
			// position++;
			col.addSeries(s);
		}

		NewOkCancelDialog d = new NewOkCancelDialog(null, false, col);
		d.setLocationRelativeTo(null);
		d.setVisible(true);

	}

	@Override
	public double calculate(double x, double[] vals) {
		int pos = elNumber;
		double val = 0.0;
		for (Iterator<ICalculate> iterator = this.baseFunctions.iterator(); iterator.hasNext();) {
			ICalculate func = iterator.next();
			val += func.calculate(x) * vals[pos];
			pos++;
		}
		return val;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see solvers.IElement#generateAll()
	 */
	@Override
	public void generateAll() {
		Quadrature gau = new GaussQuadrature(QuadraturePointsNumber);
		// final EquationParameters finalEP = this.eParams;

		// generating values
		data = new ElementMatrix(pos);
		for (int i = 0; i < data.vector.length; i++) {
			final ICalculate phi1 = baseFunctions.get(i);
			double[] bounds = phi1.getBounds();
			bounds[0] = Math.max(left, bounds[0]);
			bounds[1] = Math.min(right, bounds[1]);
			for (int j = 0; j < data.vector.length; j++) {
				final ICalculate phi2 = baseFunctions.get(j);
				double value = gau.integrate(bounds[0], bounds[1], new IFunction1D() {

					@Override
					public double calculate(double x) {
						double[] r1 = phi2.calculateAll(x);
						double[] r2 = phi1.calculateAll(x);
						return eParams.p.calculate(x) * r1[1] * r2[1] + eParams.w.calculate(x) * r1[1] * r2[0] + eParams.q.calculate(x) * r1[0] * r2[0];
					}

					@Override
					public double calculateDerivaty(double x) {

						return 0;
					}
				});
				data.matrix[i][j] = (value);
			}
			data.vector[i] = gau.integrate(bounds[0], bounds[1], new IFunction1D() {

				@Override
				public double calculate(double x) {
					double r1 = phi1.calculate(x);
					return eParams.f.calculate(x) * r1;
				}

				@Override
				public double calculateDerivaty(double x) {
					return 0.0;
				}
			});
		}

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see solvers.IElement#generateFe()
	 */
	@Override
	public double[] generateFe() {

		return null;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see solvers.IElement#generatePe()
	 */
	@Override
	public double[][] generatePe() {

		return null;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see solvers.IElement#generateQe()
	 */
	@Override
	public double[][] generateQe() {

		return null;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see solvers.IElement#generateWe()
	 */
	@Override
	public double[][] generateWe() {

		return null;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see solvers.IElement#getAll()
	 */
	@Override
	public ElementMatrix getAll() {
		return data;
	}

	@Override
	public int lastNumber() {
		return this.elNumber + baseFunctions.size() - 1;
	}

	public static void main(String[] args) {
		new EnrichedLinearElementType2(new EquationParameters(), 0.0, 1.0, 0, 5, new CubicSpline(), 2.3);
	}

}
